package com.leo.tool.jdk.jdk5;

import com.leo.tool.jdk.jdk5.lock.AqsMutex;
import com.leo.tool.jdk.jdk5.lock.Mutex;
import com.leo.tool.jdk.jdk5.lock.ParkMutex;
import org.junit.Assert;
import org.junit.Test;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class MutexTest {

    volatile int counter = 0;

    Mutex mutex;

    @Test
    public void testAqsMutex() throws ExecutionException, InterruptedException {
        mutex = new AqsMutex();
        test();
    }

    @Test
    public void testParkMutex() throws ExecutionException, InterruptedException {
        mutex = new ParkMutex();
        test();
    }

    private void test() throws InterruptedException, ExecutionException {
        counter = 0;
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(this::increase);
        CompletableFuture<Void> future2 = CompletableFuture.runAsync(this::increase);
        CompletableFuture<Void> future3 = CompletableFuture.runAsync(this::increase);
        CompletableFuture.allOf(future1, future2, future3).get();
        Assert.assertNotEquals(3_000_000, counter);

        counter = 0;
        future1 = CompletableFuture.runAsync(this::lockedIncrease);
        future2 = CompletableFuture.runAsync(this::lockedIncrease);
        future3 = CompletableFuture.runAsync(this::lockedIncrease);
        CompletableFuture.allOf(future1, future2, future3).get();
        Assert.assertEquals(3_000_000, counter);
    }

    private void lockedIncrease() {
        mutex.lock();
        increase();
        mutex.unlock();
    }

    private void increase() {
        for (int i = 0; i < 1_000_000; i++) {
            counter++;
        }
    }
}
